package com.ruoyi.cs.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.Response;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.RSAutil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.pay.HCPayConfig;
import com.ruoyi.common.utils.sign.Base64;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.cs.domain.*;
import com.ruoyi.cs.mapper.*;
import com.ruoyi.cs.service.CommonService;
import com.ruoyi.cs.service.IHCPayService;
import com.ruoyi.system.mapper.SysConfigMapper;
import com.ruoyi.system.mapper.SysDictDataMapper;
import com.ruoyi.system.service.impl.SysConfigServiceImpl;
import com.thoughtworks.xstream.XStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@SuppressWarnings("all")
public class HCPayServiceImpl implements IHCPayService {
    private static final Logger log = LoggerFactory.getLogger(HCPayServiceImpl.class);

    @Autowired
    private TUserMapper userMapper;

    @Value("${ruoyi.hcpayNotify}")
    private String hcpayNotify;

    @Value("${ruoyi.hcpaySM}")
    private String hcpaySM;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private TRechargeMapper tRechargeMapper;

    @Autowired
    private CommonService commonService;

    @Autowired
    private SysConfigServiceImpl sysConfigService;

    @Autowired
    private SysConfigMapper sysConfigMapper;

    @Autowired
    private TUserAuthenticationMapper tUserAuthenticationMapper;

    @Autowired
    private TUserSyMapper tUserSyMapper;

    @Autowired
    private TBalanceChangeMapper tBalanceChangeMapper;

    @Autowired
    private SysDictDataMapper sysDictDataMapper;

    public HCPayServiceImpl() throws IOException {
    }

    @Override
    public Response<Map> recharge(String userId, BigDecimal czMoney, String czEquipment) throws Exception {
        TUser tUser = userMapper.selectTUserById(userId);
        BigDecimal giveFee = new BigDecimal("0");
        try {
            giveFee = commonService.rechargeVerification(tUser, czMoney);
        } catch (Exception e) {
            return Response.fail(e.getMessage());
        }

        String out_trade_no = DateUtils.dateTimeNow() + IdUtils.fastUUID().substring(0, 8);
        BigDecimal fee = czMoney.multiply(new BigDecimal(6.5)).setScale(2, BigDecimal.ROUND_HALF_UP);
        HCPayRequest dto = new HCPayRequest();
        dto.setMerchantOrderNo(out_trade_no);
        dto.setMerchantNo(HCPayConfig.MerchantNo);
        dto.setPayType(HCPayConfig.PAYTYPE_ZFB);
        dto.setAmount(fee.toString());
        dto.setSubject(HCPayConfig.SUBJECT);
        dto.setDesc(HCPayConfig.SUBJECT);
        dto.setAdviceUrl(hcpayNotify);
        dto.setSubAppid("1");
        dto.setCompanyNo("1");
        dto.setUserId("1");
        dto.setSubMerchantType(HCPayConfig.SUBMERCHANTTYPE);
        dto.setPayWay(HCPayConfig.PAYWAY_ZFB);
        dto.setRandomStr(out_trade_no);
        String xml = postDoPayXML(HCPayConfig.ApiBase_0, dto);

        StringBuilder stringBuilder = new StringBuilder();
        StringBuilder ciphertext= stringBuilder.append(HCPayConfig.HCPAY_QR_CODE_PREFIX).append(xml);

        /**密文存放在redis里面,过期时间5分钟*/
        String uuid = UUID.randomUUID().toString().replace("-", "");
        String verifyKey = Constants.HCPAY_CODE_KEY + uuid;
        redisCache.setCacheObject(verifyKey, xml, 30, TimeUnit.MINUTES);
        /**支付宝扫码请求的地址*/
        String reurl = hcpaySM + uuid;
        log.info("汇潮支付PC端：{}，{}", uuid, reurl);

        String picurl = null;
        try {
            /**生产二维码图片*/
            picurl = commonService.scQrCodeImge(reurl);
        } catch (Exception e) {
            log.error("汇潮支付生产二维码订单异常:{}", e.getMessage());
            e.printStackTrace();
            return Response.fail("发送请求失败");
        }

        TRecharge tRecharge = new TRecharge();
        tRecharge.setUserId(userId);
        tRecharge.setCzId(out_trade_no);
        tRecharge.setDelFlag(Constants.SUCCESS);
        tRecharge.setCzType(Constants.ALIPAY);
        /**支付结果  0 待充值 1充值成功 2充值失败*/
        tRecharge.setCzStatus(Constants.CZSTATUS0);
        /**交易类型*/
        tRecharge.setCzEquipment(czEquipment);
        tRecharge.setCreateTime(DateUtils.getNowDate());
        tRecharge.setGiveFee(giveFee);
        tRecharge.setCzMoney(czMoney);
        tRecharge.setCzPlatform(Constants.CZPLATFORM1);
        tRecharge.setUserType(tUser.getUserType());
        if (StringUtils.isNotEmpty(tUser.getUserPromotersId())) {
            tRecharge.setUserPromotersId(tUser.getUserPromotersId());
        }
        int count = tRechargeMapper.insertTRecharge(tRecharge);
        if (count > 0) {
            Map map = new HashMap();
            map.put("picUrl", picurl);
            map.put("czId", out_trade_no);
            map.put("totalFee", czMoney);
            map.put("url", ciphertext.toString());
            log.info("汇潮支付订单生产：参数信息：{}，支付金额：{},订单号：{}", JSON.toJSONString(tRecharge), fee, out_trade_no);
            return Response.success(map);
        } else {
            log.error("汇潮支付充值记录表插入失败：参数信息：{}，支付金额：{},订单号：{}", JSON.toJSONString(tRecharge), fee, out_trade_no);
            return Response.fail("充值窗口异常，请联系管理员处理!");
        }
    }

    @Override
    public String hcPayNotify(HttpServletRequest request) {
        Map<String, String> params = convertRequestParamsToMap(request); // 将异步通知中收到的待验证所有参数都存放到map中
        String paramsJson = JSON.toJSONString(params);
        log.info("汇潮支付回调，{}", paramsJson);
        try {
            String SignInfo = params.get("SignInfo");
            String merNo = params.get("MerNo");
            String billNo = params.get("BillNo");
            String orderNo = params.get("OrderNo");
            String amount = params.get("Amount");
            String succeed = params.get("Succeed");
            String payType = params.get("PayType");
            String signInfo = params.get("SignInfo");
            // 生成查询签名
            boolean signVerified = false;
            signVerified = this.generateQuerySign(merNo, billNo, orderNo, amount, succeed, signInfo);

            if (signVerified) {
                TRecharge tRecharge = tRechargeMapper.selectTRechargeById(billNo);
                String platform = tRecharge == null ? "" : tRecharge.getCzPlatform();
                Map<String, String> paramsMap = JSONObject.parseObject(paramsJson, Map.class);
                log.info("汇潮回调签名认证成功");
                if (tRecharge != null) {
                    BigDecimal bg = tRecharge.getCzMoney();
                    BigDecimal fee = bg.multiply(new BigDecimal(6.5)).setScale(2, BigDecimal.ROUND_HALF_UP);
                    // 支付成功
                    if (HCPayConfig.SUCCEED_88.equals(succeed)) {
                        // 处理支付成功逻辑
                        if (Constants.CZSTATUS0.equals(tRecharge.getCzStatus())) {
                            /**充值成功处理*/
                            commonService.czSuccessHandle(tRecharge,billNo,orderNo,paramsJson);
                        } else {
                            log.error("用户充值操作已完成,请求参数:{}", params.toString());
                        }
                    } else if (HCPayConfig.SUCCEED_00.equals(succeed)) {
                        /**充值失败处理*/
                        commonService.czFailHandle(tRecharge,billNo,orderNo,paramsJson);
                        return "success";
                    } else {
                        log.error("没有处理回调业务，交易状态：{},params:{}", succeed, paramsJson);
                    }
                    return "success";
                } else {
                    log.error("查询充值订单信息为空,请求参数：{}", paramsJson);
                    return "failure";
                }
            } else {
                log.info("汇潮回调签名认证失败，signVerified=false, paramsJson:{}", paramsJson);
                return "failure";
            }
        } catch (Exception e) {
            log.error("回调异常,paramsJson:{},errorMsg:{}", paramsJson, e.getMessage());
            return "failure";
        }
    }

    @Override
    public String paySM(String uuid) {
        /**密文存放在redis里面,过期时间5分钟*/
        String verifyKey = Constants.HCPAY_CODE_KEY + uuid;
        String value = redisCache.getCacheObject(verifyKey);
        if (value != null) {
            redisCache.deleteObject(verifyKey);
        }
        value = value == null ? "" : value;
        return value;
    }


    public static String postDoPayXML(String url, HCPayRequest dto) throws Exception {
        String res = null;
        try {
            String signContent = "AdviceUrl=" + dto.getAdviceUrl() + "&Amount=" + dto.getAmount() +
                    "&MerchantNo=" + dto.getMerchantNo() + "&MerchantOrderNo=" + dto.getMerchantOrderNo() +
                    "&PayType=" + dto.getPayType() + "&RandomStr=" + dto.getRandomStr();
            String sign = RSAutil.sign(signContent, RSAutil.getPrivateKey(HCPayConfig.priKey));
            dto.setSignInfo(sign);
            String xml = makeDoPayXML(dto);
            return xml;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String makeDoPayXML(HCPayRequest dto) {
        /**
         * 拼接成Xml明文
         */
        XStream xStream = new XStream();
        xStream.alias("root", HCPayRefundRequest.class);
        String requestDomain = xStream.toXML(dto);
        requestDomain = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + requestDomain;
        //Xml明文进行Base64编码
        requestDomain = Base64.encode(requestDomain);
        return requestDomain;
    }


    public static boolean generateQuerySign(String merNo, String BillNo, String OrderNo, String Amount, String Succeed, String signInfo) {
        boolean sign = false;
        try {
            String plain = "MerNo=" + merNo + "&" + "BillNo=" + BillNo + "&" + "OrderNo=" + OrderNo + "&" + "Amount=" + Amount + "&" + "Succeed=" + Succeed;
            sign = RSAutil.verify(plain, RSAutil.getPublicKey(HCPayConfig.pubkey), signInfo);
        } catch (Exception e) {
            System.out.println("签名出错：" + e.getMessage());
            return false;
        }
        return sign;
    }

    public Map<String, String> convertRequestParamsToMap(HttpServletRequest request) {
        Map<String, String> retMap = new HashMap<String, String>();
        Set<Map.Entry<String, String[]>> entrySet = request.getParameterMap().entrySet();
        for (Map.Entry<String, String[]> entry : entrySet) {
            String name = entry.getKey();
            String[] values = entry.getValue();
            int valLen = values.length;
            if (valLen == 1) {
                retMap.put(name, values[0]);
            } else if (valLen > 1) {
                StringBuilder sb = new StringBuilder();
                for (String val : values) {
                    sb.append(",").append(val);
                }
                retMap.put(name, sb.toString().substring(1));
            } else {
                retMap.put(name, "");
            }
        }
        return retMap;
    }
}
